/*
 * Copyright (C) 2000-2008 Jens Nixdorf and various contributors
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to
 * deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 * sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies of the Software, its documentation and marketing & publicity
 * materials, and acknowledgment shall be given in the documentation, materials
 * and software packages that this Software was used.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
package org.mopore.jat.util;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.jar.Attributes;
import java.util.jar.JarInputStream;
import java.util.jar.Manifest;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.mopore.jat.plugin.Email;
import org.mopore.jat.plugin.PluginException;

public class MetaInformationService {
	
	
	private static final String CAN_NOT_PROVIDE_EMAIL = "Can not provide email address of project head";
	private static final String TEXTS_ABOUT_TXT_PATH = "/texts/about.txt";
	private static final String NO_MANIFEST = "can not read manifest!";
	private static final String PROJECT_HEAD = "Project-Head";
	private static final String PROJECT_HEAD_EMAIL = "Project-Head-Email";
	private static final String IMPLEMENTATION_VENDOR = "Implementation-Vendor";
	private static final String IMPLEMENTATION_VERSION = "Implementation-Version";
	private static final String IMPLEMENTATION_TITLE = "Implementation-Title";
	private static final String ABOUT_TEXT = "About-text";

	
	private static Map<String, String> entries;
	
	public static void main(String[] args) throws IOException {
		readManifest();
	}
	
	
	
	private static void assertEntriesLoaded() {
		
		 final Log log = LogFactory.getLog( MetaInformationService.class );
		
		if ( entries == null ) {
			try {
				entries = readManifest();
			} catch (Exception e) {
				String errorMessage = "Can not read Manifest!";
				log.error( errorMessage, e );
				throw new InternalError( errorMessage );
			}
		}
	}
	
	
	public static String readTitle() {
		assertEntriesLoaded();
		return entries.get( IMPLEMENTATION_TITLE );
	}
	
	
	public static Version readVersion() {
		assertEntriesLoaded();
		
		String versionString = entries.get( IMPLEMENTATION_VERSION );
		
		if ( versionString.equals( "x-X-X-X")) {
			versionString = "r-0-0-0";
		}
		Version version = new Version( versionString );
		
		return version;
	}
	
	
	public static String readVendor() {
		assertEntriesLoaded();
		return entries.get( IMPLEMENTATION_VENDOR );
	}	
	
	
	public static String readProjectHeadName() {
		assertEntriesLoaded();
		return entries.get( PROJECT_HEAD );
	}	
	
	
	public static Email readProjectHeadEmail() {
		
		Log log = LogFactory.getLog(MetaInformationService.class.getName());
		
		assertEntriesLoaded();
		
		String emailString = entries.get( PROJECT_HEAD_EMAIL );
		Email email;
		try {
			email = new Email( emailString );
		} catch (PluginException e) {
			log.error( CAN_NOT_PROVIDE_EMAIL, e );
			throw new InternalError( CAN_NOT_PROVIDE_EMAIL );
		}
		
		return email;
	}		
	
	
	
	public static String readAboutText() {
		
		final Log log = LogFactory.getLog(MetaInformationService.class.getName());
		
		String aboutText = entries.get( ABOUT_TEXT );
		
		if ( aboutText == null ) {
			InputStream inputStream = 
				MetaInformationService.class.getResourceAsStream( TEXTS_ABOUT_TXT_PATH );
			
			BufferedReader reader = 
				new BufferedReader( new InputStreamReader( inputStream ) );
			
			try {
				StringBuilder b = new StringBuilder();
				String line = reader.readLine();
				
				while ( line != null ) {
					b.append( "\n" );
					b.append( line );
					line = reader.readLine();
				}
				
				inputStream.close();
				reader.close();
				
				aboutText = b.toString();
				entries.put( ABOUT_TEXT, aboutText );
			} catch (IOException e) {
				log.error( "Could not read about dialog", e );
			}
		}
		
		return aboutText;
	}
	
	

	private static Map<String, String> readManifest() throws MalformedURLException, IOException {
		
		final Log log = 
			LogFactory.getLog(MetaInformationService.class.getName() );
		
		Manifest manifest = null;

		InputStream inputStream = null;
		try {
			URL url = MetaInformationService.class.getProtectionDomain().getCodeSource().getLocation();
			JarInputStream jarInputStream = new JarInputStream( url.openStream() );
			manifest = jarInputStream.getManifest();
			inputStream = jarInputStream;
		    
			if ( manifest == null ) {
				log.info( "can not read manifest from jar using classpath..." );
				inputStream.close();
			
				inputStream = 
					MetaInformationService.class.getResourceAsStream( 
							"/META-INF/MANIFEST.MF" );
				manifest = new Manifest( inputStream );
			}
		}
		catch (Exception e) {
			log.error( NO_MANIFEST, e );
		}
			
		if ( manifest == null ) {
			log.error( NO_MANIFEST );
			throw new InternalError( NO_MANIFEST );
		}
		
		log.info( "Got a manifest..." );
		
		String[] names = new String[] { 
				IMPLEMENTATION_TITLE,
				IMPLEMENTATION_VERSION,
				IMPLEMENTATION_VENDOR,
				PROJECT_HEAD,
				PROJECT_HEAD_EMAIL
			};
		
		Map<String, String> entries = new HashMap<String, String>();
		
		Attributes atributes = manifest.getMainAttributes();
		for (String string : names) {
			String value = atributes.getValue( string );
			entries.put( string, value );
		}
		
		if ( inputStream != null ) {
			inputStream.close();
		}
		
		return entries;
	}

}
